#include "fatfs_driver.h"
#include <errno.h>
#include <sys/stat.h>

static const char *TAG = "fatfs_driver";

sdmmc_card_t *card;

esp_err_t fatfs_write_file(const char *path, char *data)
{
    const char *last_slash = strrchr(path, '/');
    if (!last_slash) {
        ESP_LOGE(TAG, "Invalid path: %s", path);
        return ESP_FAIL;
    }

    char dir[256];
    size_t dir_len = last_slash - path;
    strncpy(dir, path, dir_len);
    dir[dir_len] = '\0';

    // 逐级创建 /storage 之后的子目录
    char subpath[256] = "/storage";
    const char *sub = dir + strlen("/storage");  // 跳过 "/storage"
    while (*sub == '/') sub++; // 跳过多个斜杠

    char *token;
    char tmp[256];
    strncpy(tmp, sub, sizeof(tmp));
    token = strtok(tmp, "/");

    while (token) {
        strcat(subpath, "/");
        strcat(subpath, token);
        if (mkdir(subpath, 0777) != 0 && errno != EEXIST) {
            ESP_LOGE(TAG, "Failed to create dir: %s (%s)", subpath, strerror(errno));
            return ESP_FAIL;
        }
        token = strtok(NULL, "/");
    }

    // 写入文件
    FILE *f = fopen(path, "w");
    if (!f) {
        ESP_LOGE(TAG, "Failed to open file: %s", path);
        return ESP_FAIL;
    }
    fprintf(f, "%s", data);
    fclose(f);
    ESP_LOGI(TAG, "File written: %s", path);
    return ESP_OK;
}

// 读文件内容 path是路径
esp_err_t fatfs_read_file(const char *path, char *data)
{
    ESP_LOGI(TAG, "Reading file %s", path);
    FILE *f = fopen(path, "r"); // 以只读方式打开文件
    if (f == NULL)
    {
        ESP_LOGE(TAG, "Failed to open file for reading");
        return ESP_FAIL;
    }
    char line[EXAMPLE_MAX_CHAR_SIZE]; // 定义一个字符串数组
    fgets(line, sizeof(line), f);     // 获取文件中的内容到字符串数组
    fclose(f);                        // 关闭文件

    // strip newline
    char *pos = strchr(line, '\n'); // 查找字符串中的“\n”并返回其位置
    if (pos)
    {
        *pos = '\0'; // 把\n替换成\0
    }
    ESP_LOGI(TAG, "Read from file: '%s'", line); // 把数组内容输出到终端
    strcpy(data, line);
    return ESP_OK;
}

esp_err_t sd_fatfs_init(void)
{
    esp_err_t ret;

    esp_vfs_fat_sdmmc_mount_config_t mount_config = {
        .format_if_mount_failed = true,    // 如果挂载不成功是否需要格式化SD卡
        .max_files = 5,                    // 允许打开的最大文件数
        .allocation_unit_size = 16 * 1024, // 分配单元大小
    };

    const char mount_point[] = MOUNT_POINT;
    ESP_LOGI(TAG, "Initializing SD card");
    ESP_LOGI(TAG, "Using SDMMC peripheral");

    sdmmc_host_t host = SDMMC_HOST_DEFAULT();                      // SDMMC主机接口配置
    sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); // SDMMC插槽配置
    slot_config.width = 1;                                         // 设置为1线SD模式
    slot_config.clk = BSP_SD_CLK;
    slot_config.cmd = BSP_SD_CMD;
    slot_config.d0 = BSP_SD_D0;
    slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP; // 打开内部上拉电阻

    ESP_LOGI(TAG, "Mounting filesystem");
    ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card); // 挂载SD卡

    if (ret != ESP_OK)
    { // 如果没有挂载成功
        if (ret == ESP_FAIL)
        { // 如果挂载失败
            ESP_LOGE(TAG, "Failed to mount filesystem. ");
        }
        else
        { // 如果是其它错误 打印错误名称
            ESP_LOGE(TAG, "Failed to initialize the card (%s). ", esp_err_to_name(ret));
        }
        return ESP_FAIL;
    }
    ESP_LOGI(TAG, "Filesystem mounted"); // 提示挂载成功
    sdmmc_card_print_info(stdout, card); // 终端打印SD卡的一些信息
    return ESP_OK;
}

esp_err_t sd_fatfs_deinit(void)
{
    esp_err_t ret;
    ret = esp_vfs_fat_sdcard_unmount(MOUNT_POINT, card);
    if (ret != ESP_OK)
    {
        ESP_LOGI(TAG, "SD unmount fail");
    }
    else
    {
        ESP_LOGI(TAG, "SD unmounted");
    }
    return ret;
}

esp_err_t spi_flash_fatfs_init(void)
{
    const char *base_path = MOUNT_POINT;

    esp_vfs_fat_mount_config_t mount_config = {
        .max_files = 5,
        .format_if_mount_failed = true,
        .allocation_unit_size = 16 * 1024};

    wl_handle_t wl_handle = WL_INVALID_HANDLE;

    esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(base_path, "storage", &mount_config, &wl_handle);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err));
        return ESP_FAIL;
    }
    ESP_LOGI(TAG, "FATFS mounted on %s", base_path);
    return ESP_OK;
}

esp_err_t fatfs_init(void)
{
    if (sd_fatfs_init() != ESP_OK)
    {
        spi_flash_fatfs_init();
    }
    return ESP_OK;
}